// Copyright (c) 2023 刻BITTER
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.


#pragma once

#include "ioxx.hpp"


namespace shift_io {
    // led or seg7 led driver using 595,
    // functions can also be used in serial communication to other chip.
    // before sending bits, configure SCLK, RCLK, DS pin as output.


    enum class out_order {
        lsb_first = 0x01,
        msb_first = 0x80
    };

    template <typename PinType>
    inline void shift_out(uint_fast8_t data, const PinType &ds, const PinType &sclk, out_order order) {
        for (uint8_t i = 8; i; --i) {
            if (data & static_cast<uint8_t>(order))
                ds.set();
            else
                ds.clr();

            sclk.toggle();

            if (order == out_order::msb_first)
                data <<= 1;
            else
                data >>= 1;

            sclk.toggle();
        }
    }


    enum class in_order {
        lsb_first = 0x80,
        msb_first = 0x01
    };


    template <typename PinType>
    inline uint8_t shift_in(const PinType &ds, const PinType &sclk, in_order order) {
        uint8_t data = 0;
        for (uint8_t i = 8; i; --i) {
            sclk.toggle();

            if (order == in_order::msb_first)
                data <<= 1;
            else
                data >>= 1;

            sclk.toggle();

            if (ds.get())
                data |= static_cast<uint8_t>(order);
        }

        return data;
    }

}  // namespace shift_io